#include "qopenharmonyplayercontrol.h"
#include "qopenharmonyplayerservice.h"
#include "qopenharmonyplayer.h"
#include "qopenharmonywindowcontrol.h"

#include <QtCore/qcoreapplication.h>
#include <QtCore/qmath.h>
#include <qaudio.h>


QOpenHarmonyPlayerControl::QOpenHarmonyPlayerControl(QObject *parent)
    : QMediaPlayerControl(parent)
{
    m_player = new QOpenHarmonyPlayer();
    connect(m_player,SIGNAL(bufferingChanged(qint32)),
            this,SLOT(onBufferingChanged(qint32)));
    connect(m_player,SIGNAL(error(int,QString)),
            this,SLOT(onError(int,QString)));
    connect(m_player,SIGNAL(stateChanged(qint32)),
            this,SLOT(onStateChanged(qint32)));
    connect(m_player,SIGNAL(videoSizeChanged(qint32,qint32)),
            this,SLOT(onVideoSizeChanged(qint32,qint32)));
    connect(m_player,SIGNAL(progressChanged(qint64)),
            this,SIGNAL(positionChanged(qint64)));
    connect(m_player,SIGNAL(durationChanged(qint64)),
            this,SIGNAL(durationChanged(qint64)));
    connect(m_player,SIGNAL(audioAvailableChanged(bool)),
            this,SLOT(setAudioAvailable(bool)));
    connect(m_player,SIGNAL(videoAvailableChanged(bool)),
            this,SLOT(setVideoAvailable(bool)));
    connect(m_player,SIGNAL(seekableChanged(bool)),
            this,SLOT(setSeekable(bool)));
    connect(m_player,SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
            this,SLOT(setMediaStatus(QMediaPlayer::MediaStatus)));

}

QOpenHarmonyPlayerControl::~QOpenHarmonyPlayerControl()
{
    m_player->release();
    delete m_player;
}

void QOpenHarmonyPlayerControl::setVideoOutput(QOpenHarmonyWindowControl *control)
{
    if (control == nullptr)
        return;
    m_control = control;
    connect(m_control, &QOpenHarmonyWindowControl::windowCreated, this, &QOpenHarmonyPlayerControl::onWindowCreated);
}

QMediaPlayer::State QOpenHarmonyPlayerControl::state() const
{
     AVPlayerState state = m_player->state();
     if (state == AV_PLAYING)
         return QMediaPlayer::PlayingState;
     else if (state == AV_PAUSED)
         return QMediaPlayer::PausedState;
     else
         return QMediaPlayer::StoppedState;
}

QMediaPlayer::MediaStatus QOpenHarmonyPlayerControl::mediaStatus() const
{
    return m_status;
}

qint64 QOpenHarmonyPlayerControl::duration() const
{
    return m_player->getDuration();
}

qint64 QOpenHarmonyPlayerControl::position() const
{
    if (m_status == QMediaPlayer::EndOfMedia)
        return duration();
    return m_player->getCurrentPosition();
}

void QOpenHarmonyPlayerControl::setPosition(qint64 position)
{
    if (m_status == QMediaPlayer::EndOfMedia) {
        m_status = QMediaPlayer::LoadedMedia;
        emit mediaStatusChanged(m_status);
    }
    const int seekPosition = (position > INT_MAX) ? INT_MAX : position;

    if (seekPosition == this->position())
        return;

    m_player->seekTo(seekPosition);

    Q_EMIT positionChanged(seekPosition);
}

int QOpenHarmonyPlayerControl::volume() const
{
    return m_volume;
}

void QOpenHarmonyPlayerControl::setVolume(int volume)
{
    if (m_volume == volume)
        return;
    m_player->setVolume(volume);

    Q_EMIT volumeChanged(volume);
}

bool QOpenHarmonyPlayerControl::isMuted() const
{
    return m_muted;
}

void QOpenHarmonyPlayerControl::setMuted(bool muted)
{
    if (m_muted == muted)
        return;

    m_player->setMuted(muted);

    Q_EMIT mutedChanged(muted);
}

int QOpenHarmonyPlayerControl::bufferStatus() const
{
    return m_bufferFilled ? 100 : 0;
}

bool QOpenHarmonyPlayerControl::isAudioAvailable() const
{
    return m_audioAvailable;
}

bool QOpenHarmonyPlayerControl::isVideoAvailable() const
{
    return m_videoAvailable;
}

bool QOpenHarmonyPlayerControl::isSeekable() const
{
    return m_seekable;
}

QMediaTimeRange QOpenHarmonyPlayerControl::availablePlaybackRanges() const
{
    return m_availablePlaybackRange;
}

void QOpenHarmonyPlayerControl::updateAvailablePlaybackRanges()
{
    if (m_buffering) {
        const qint64 pos = position();
        const qint64 end = (duration() / 100) * m_bufferPercent;
        m_availablePlaybackRange.addInterval(pos, end);
    } else if (m_seekable) {
        m_availablePlaybackRange = QMediaTimeRange(0, duration());
    } else {
        m_availablePlaybackRange = QMediaTimeRange();
    }

    Q_EMIT availablePlaybackRangesChanged(m_availablePlaybackRange);
}

qreal QOpenHarmonyPlayerControl::playbackRate() const
{
    return m_player->playbackRate();
}

void QOpenHarmonyPlayerControl::setPlaybackRate(qreal rate)
{
    if (m_player->setPlaybackRate(rate)) {
        emit playbackRateChanged(rate);
    }
}

QMediaContent QOpenHarmonyPlayerControl::media() const
{
    return m_media;
}

const QIODevice *QOpenHarmonyPlayerControl::mediaStream() const
{
    return m_stream;
}

void QOpenHarmonyPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream)
{
    if (m_media == media && m_stream == stream)
        return;

    m_media = media;
    m_stream = stream;
    if (media.isNull()) {
        m_status = QMediaPlayer::NoMedia;
    } else {
        m_status = QMediaPlayer::LoadingMedia;
        m_player->setDataSource(media.request());
        m_status = QMediaPlayer::LoadedMedia;
    }

    Q_EMIT mediaChanged(media);
}

void QOpenHarmonyPlayerControl::play()
{
    playOrPause(QMediaPlayer::PlayingState);
}

void QOpenHarmonyPlayerControl::pause()
{
    playOrPause(QMediaPlayer::PausedState);
}

void QOpenHarmonyPlayerControl::playOrPause(QMediaPlayer::State state)
{
    if (m_status == QMediaPlayer::NoMedia || state == QMediaPlayer::StoppedState)
        return;
    if (m_status == QMediaPlayer::InvalidMedia) {
        setMedia(m_media, m_stream);
        if (m_error != QMediaPlayer::NoError)
            return;
    }

    if (state == QMediaPlayer::PausedState)
        m_player->pause();
    else
        m_player->play();

    emit stateChanged(state);
}

void QOpenHarmonyPlayerControl::stop()
{
    m_player->stop();
    emit stateChanged(QMediaPlayer::StoppedState);
}

void QOpenHarmonyPlayerControl::setDisplay()
{
    m_player->setDisplay(m_control->nativeWindow());
}

QSize QOpenHarmonyPlayerControl::videoSize() const
{
    return m_videoSize;
}

void QOpenHarmonyPlayerControl::setSeekable(bool seekable)
{
    if (m_seekable == seekable)
        return;

    m_seekable = seekable;
    Q_EMIT seekableChanged(m_seekable);
}

void QOpenHarmonyPlayerControl::setAudioAvailable(bool available)
{
    if (m_audioAvailable == available)
        return;

    m_audioAvailable = available;
    Q_EMIT videoAvailableChanged(m_audioAvailable);
}

void QOpenHarmonyPlayerControl::setVideoAvailable(bool available)
{
    if (m_videoAvailable == available)
        return;

    m_videoAvailable = available;
    Q_EMIT videoAvailableChanged(m_videoAvailable);
}

void QOpenHarmonyPlayerControl::onWindowCreated()
{
    setDisplay();
}

void QOpenHarmonyPlayerControl::onStateChanged(qint32)
{
    emit stateChanged(state());
}

void QOpenHarmonyPlayerControl::onVideoSizeChanged(qint32 width, qint32 height)
{
    QSize newSize(width, height);

    if (width == 0 || height == 0 || newSize == m_videoSize)
        return;

    m_videoSize = newSize;
}

void QOpenHarmonyPlayerControl::setMediaStatus(QMediaPlayer::MediaStatus status)
{
    if (m_status == status)
        return;

    m_status = status;

    if (status == QMediaPlayer::NoMedia || status == QMediaPlayer::InvalidMedia)
        Q_EMIT durationChanged(0);

    if (status == QMediaPlayer::EndOfMedia)
        Q_EMIT positionChanged(position());

    updateBufferStatus();
}

void QOpenHarmonyPlayerControl::updateBufferStatus()
{
    bool bufferFilled = (m_status == QMediaPlayer::BufferedMedia
                         || m_status == QMediaPlayer::BufferingMedia);

    if (m_bufferFilled != bufferFilled) {
        m_bufferFilled = bufferFilled;
        Q_EMIT bufferStatusChanged(bufferStatus());
    }
}

void QOpenHarmonyPlayerControl::onBufferingChanged(qint32 percent)
{
    m_buffering = percent != 100;
    m_bufferPercent = percent;

    updateAvailablePlaybackRanges();

    if (state() != QMediaPlayer::StoppedState)
        setMediaStatus(m_buffering ? QMediaPlayer::BufferingMedia : QMediaPlayer::BufferedMedia);
}

void QOpenHarmonyPlayerControl::onError(int code, const QString &errorString)
{
    qWarning() <<"open harmony player error: " << code << errorString;
    // Todo 鸿蒙errorCode和QMediaPlayer::Error对应
    emit error(code, errorString);
}
